import { isObject } from '../utils'
import { reactive, isReactive } from './reactive'
import { createDepsMap, track, trigger } from './effect'

export interface Ref<T = any> { // ref 对象
	__v_isRef: true,
	value: T
}
export type ToRefs<T = any> = { [K in keyof T]: Ref<T[K]> }

export const isRef = (v: any): v is Ref => v ? v.__v_isRef === true : false
const convert = <T extends unknown>(val: T) =>
	isObject(val) ? reactive(val as any) : val

/** 
 * 生成Ref对象
 * @param rawVal {unknown} ref值
 * @return ref对象
 */
export function ref<T = any>(value: T): Ref<T | undefined>
export function ref(value: unknown) { return createRef(value) }
function createRef(rawVal: unknown) {
	if (isRef(rawVal)) { return rawVal }
	let value = convert(rawVal)

	let depsMap = createDepsMap()
	let r = {
		__v_isRef: true,
		get value() {
			track(depsMap, 'value')
			return value
		},
		set value(newVal) {
			if (rawVal !== newVal) {
				rawVal = newVal
				value = convert(newVal)
				trigger(depsMap, 'value')
			}
		}
	}
	return r
}

export function toRefs<T extends object>(object: T): ToRefs<T> {
	if (!isReactive(object)) {
		console.warn(`toRefs() 需要一个reactive对象，但收到的是一个普通对象`)
	}
	const ret: any = {}
	for (const key in object) {
		ret[key] = toRef(object, key)
	}
	return ret
}

export function toRef<T extends object, K extends keyof T>(
	object: T,
	key: K
): Ref<T[K]> {
	return {
		__v_isRef: true,
		get value(): any {
			return object[key]
		},
		set value(newVal) {
			object[key] = newVal
		}
	} as any
}